package gvscanreader;



/**
 * Progetto dbsistemattack
 * Simulatore di attacchi da parte di minacce ad un sistema informatico
 * 
 * <copyright> gpl </copyright>
 * <author>Roberto Bertolotti</author>
 * <email>robeberto@gmail.com</email>
 * <date>2012-08-10</date>
 */

import java.sql.*;
import java.util.ArrayList;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 *
 * Classe dedicata alla gestione del Database.
 * Gestisce l'apertura e la chiusura della connessione col Database
 * Fornisce i metodi per l'esecuzione delle query sul Database
 */
public class DBConnector implements DBConnectorInterface {
   private String nomeDB;       // Nome del Database a cui connettersi
   private String nomeUtente;   // Nome utente utilizzato per la connessione al Database
   private String pwdUtente;    // Password usata per la connessione al Database
   private String errore;       // Raccoglie informazioni riguardo l'ultima eccezione sollevata
   private Connection connection;       // La connessione col Database
   private boolean connesso;    // Flag che indica se la connessione è attiva o meno
   
   private ArrayList <String> oldWords;
   private ArrayList <String> newWords;

   /**
    * Crea una nuova connessione con il database
    * @param nomeDB 
    */
   public DBConnector(String nomeDB) { 
       this(nomeDB, "", ""); 
   }

   /**
    * Crea una nuova connessione con il database
    * @param nomeDB nome database
    * @param nomeUtente nome utente
    * @param pwdUtente  password
    */
   public DBConnector(String nomeDB, String nomeUtente, String pwdUtente) {
      this.nomeDB = nomeDB;
      this.nomeUtente = nomeUtente;
      this.pwdUtente = pwdUtente;
      connesso = false;
      errore = "";
      oldWords = new ArrayList <String>();
      newWords = new ArrayList <String>();
      oldWords.add("10.0.255.101");
      newWords.add("Switch 1");
      oldWords.add("10.0.255.162");
      newWords.add("Stazione di Controllo 2 (PLC1 e PLC2)");
      oldWords.add("10.0.255.163");
      newWords.add("Stazione di Ingegneria 1");
      oldWords.add("10.0.255.165");
      newWords.add("ASC");
      oldWords.add("10.0.255.171");
      newWords.add("Client Scada 1");
      oldWords.add("10.0.255.1");
      newWords.add("Stazione di Controllo 1 (altri PLC non presenti)");
      oldWords.add("10.0.255.201");
      newWords.add("Switch 2");
      oldWords.add("10.0.255.210");
      newWords.add("Firewall di Frontiera Processo-Intranet");
      oldWords.add("10.0.255.212");
      newWords.add("Firewall 1");
      oldWords.add("10.0.255.231");
      newWords.add("Stampante 1");
      oldWords.add("10.0.255.232");
      newWords.add("Stampante 2");
      oldWords.add("10.0.255.237");
      newWords.add("Client Scada 2");
      oldWords.add("10.0.255.239");
      newWords.add("Firewall 2");
      oldWords.add("10.0.255.2");
      newWords.add("Stazione di Controllo 3 (altri PLC non presenti)");
      oldWords.add("10.0.255.3");
      newWords.add("Stazione di Controllo 4 (altri PLC non presenti)");
      oldWords.add("10.0.255.4");
      newWords.add("Stazione di Controllo 5 (PLC1 e PLC2)");
      oldWords.add("10.0.255.5");
      newWords.add("Stazione di Ingegneria 2");
      oldWords.add("172.16.10.1");
      newWords.add("PLC1");
      oldWords.add("172.16.10.229");
      newWords.add("Router 1");
      oldWords.add("172.16.10.230");
      newWords.add("Router 2");
      oldWords.add("172.16.10.231");
      newWords.add("Access Point 1");
      oldWords.add("172.16.10.232");
      newWords.add("Access Point 2");
      oldWords.add("172.16.10.238");
      newWords.add("Access Point 3");
      oldWords.add("172.16.10.2");
      newWords.add("PLC2");
      oldWords.add("172.16.10.55");
      newWords.add("Switch 3");
      oldWords.add("172.16.10.5");
      newWords.add("Switch 4");
      oldWords.add("192.168.8.103");
      newWords.add("Client di Telecontrollo 1");
      oldWords.add("192.168.8.104");
      newWords.add("Client di Telecontrollo 2");
      oldWords.add("192.168.8.10");
      newWords.add("Firewall di Frontiera Intranet-Processo");
      oldWords.add("192.168.8.1");
      newWords.add("Switch 5");
      oldWords.add("192.168.8.30");
      newWords.add("Parent Server Antivirus");
      oldWords.add("192.168.8.32");
      newWords.add("Access Point 4");
   }

       // <editor-fold defaultstate="collapsed" desc="fondamentali">

   
   /**
    * Apre la connessione con il Database
    */
   public boolean connect() {
      connesso = false;
      try {

         // Carico il driver JDBC per la connessione con il database MySQL
         Class.forName("com.mysql.jdbc.Driver");

         // Controllo che il nome del Database non sia nulla
         if (!nomeDB.equals("")) {

            // Controllo se il nome utente va usato o meno per la connessione
            if (nomeUtente.equals("")) {

               // La connessione non richiede nome utente e password
               connection = DriverManager.getConnection("jdbc:mysql://localhost/" + nomeDB);
            } else {

               // La connessione richiede nome utente, controllo se necessita anche della password
               if (pwdUtente.equals("")) {

                  // La connessione non necessita di password
                  connection = DriverManager.getConnection("jdbc:mysql://localhost/" + nomeDB + "?user=" + nomeUtente);
               } else {

                  // La connessione necessita della password
                  connection = DriverManager.getConnection("jdbc:mysql://localhost/" + nomeDB + "?user=" + nomeUtente + "&password=" + pwdUtente);
               }
            }

            // La connessione è avvenuta con successo
            connesso = true;
         } else {
            System.err.println("Manca il nome del database!!");
            System.err.println("Scrivere il nome del database da utilizzare all'interno del file \"config.xml\"");
            System.exit(0);
         }
      } catch (Exception e) {
          errore = e.getMessage();
          System.err.println(errore);
      }
      System.out.println("connesso");
      return connesso;
   }
   
   /**
    *  Chiude la connessione con il Database
    */
    @Override
   public void disconnect() {
      try {
         connection.close();
         connesso = false;
      } catch (Exception e) { e.printStackTrace(); }
   }

   
    
   /**
    * Esegue una query di selezione dati sul Database
    * query: una stringa che rappresenta un'istruzione SQL di tipo SELECT da eseguire
    * ritorna un ArrayList contenente tutte le tuple del risultato
    * Verrà prodotto il comando SQL: SELECT "+campo+" FROM "+ nomeTabella+" WHERE "+condizione;
    * @param nomeTabella nome della tabella su cui si vuole eseguire la query
    * @param campo nome del campo di cui si è interessati ad ottenere il valore (* indica tutti i campi)
    * @param condizione condizione che deve soddisfare la query. Può essere null
    * @param groupBy nome dei campi sui quali si vuole raggruppare. Può essere null
    * @return
    * @throws SQLException 
    */
    @Override
   public ArrayList query(String nomeTabella, String campo, String condizione, String groupBy) throws SQLException {

      String sQuery;
      if(nomeTabella==null) return null;
      if(campo==null) return null;
      if (condizione==null) sQuery = "SELECT "+campo+" FROM "+ nomeTabella;
      else sQuery = "SELECT "+campo+" FROM "+ nomeTabella+" WHERE "+condizione;
      if (groupBy != null) sQuery = sQuery + " GROUP BY " + groupBy;
      
      //System.out.println(sQuery);
      
      ArrayList v = null;
      String [] record;
      int colonne = 0;
      try {
         Statement stmt = connection.createStatement();     // Creo lo Statement per l'esecuzione della query
         ResultSet rs = stmt.executeQuery(sQuery);   // Ottengo il ResultSet dell'esecuzione della query
         v = new ArrayList();
         ResultSetMetaData rsmd = rs.getMetaData();
         colonne = rsmd.getColumnCount();

         while(rs.next()) {   // Creo il vettore risultato scorrendo tutto il ResultSet
            record = new String[colonne];
            for (int i=0; i<colonne; i++) record[i] = rs.getString(i+1);
            v.add( (String[]) record.clone() );
         }
         rs.close();     // Chiudo il ResultSet
         stmt.close();   // Chiudo lo Statement
      } catch (Exception e) { e.printStackTrace(); errore = e.getMessage(); }

      return v;
   }
    
   /**
    * Esegue una query di selezione dati sul Database
    * query: una stringa che rappresenta un'istruzione SQL di tipo SELECT da eseguire
    * ritorna un ArrayList contenente tutte le tuple del risultato
    * Verrà prodotto il comando SQL: SELECT "+campo+" FROM "+ nomeTabella+" WHERE "+condizione;
    * @param nomeTabella nome della tabella su cui si vuole eseguire la query
    * @param campo nome del campo di cui si è interessati ad ottenere il valore (* indica tutti i campi)
    * @param condizione condizione che deve soddisfare la query. Può essere null
    * @return
    * @throws SQLException 
    */
    @Override
   public ArrayList query(String nomeTabella, String campo, String condizione) throws SQLException {

      String sQuery;
      if(nomeTabella==null) return null;
      if(campo==null) return null;
      if (condizione==null) sQuery = "SELECT "+campo+" FROM "+ nomeTabella;
      else sQuery = "SELECT "+campo+" FROM "+ nomeTabella+" WHERE "+condizione;
      
      //System.out.println(sQuery);
      
      ArrayList v = null;
      String [] record;
      int colonne = 0;
      try {
         Statement stmt = connection.createStatement();     // Creo lo Statement per l'esecuzione della query
         ResultSet rs = stmt.executeQuery(sQuery);   // Ottengo il ResultSet dell'esecuzione della query
         v = new ArrayList();
         ResultSetMetaData rsmd = rs.getMetaData();
         colonne = rsmd.getColumnCount();

         while(rs.next()) {   // Creo il vettore risultato scorrendo tutto il ResultSet
            record = new String[colonne];
            for (int i=0; i<colonne; i++) record[i] = rs.getString(i+1);
            v.add( (String[]) record.clone() );
         }
         rs.close();     // Chiudo il ResultSet
         stmt.close();   // Chiudo lo Statement
      } catch (Exception e) { e.printStackTrace(); errore = e.getMessage(); }

      return v;
   }
    
    
    
   /**
    * Esegue un inserimento nel database.
    * Verrà prodotto il comando SQL: "INSERT INTO "+ nomeTabella+" ( "+campo+") VALUES("+valore +")" 
    * @param nomeTabella nome della tabella 
    * @param campo nome dei campi in cui si vuole inserire
    * @param valore valore dei campi in cui si vuole inserire
    * @return
    * @throws SQLException 
    */
    @Override
   public boolean insert(String nomeTabella, String campo, String valore) throws SQLException {
      //String query = "INSERT INTO "+ table_name+"  ( "+ field1, field2,...fieldN+") VALUES("
      //        +value1, value2,...valueN +")";  
      Boolean insert = true;
       
      String sInsert = "INSERT INTO "+ nomeTabella+" ( "+campo+") VALUES("+valore +")";
      
      /*for ( int i = 0; i < newWords.size(); i++ )
      {
          sInsert = sInsert.replaceAll( oldWords.get(i), oldWords.get(i) + " " + newWords.get(i) );
      }*/
      
      System.out.println(sInsert);
      
      try {
         Statement stmt = connection.createStatement();     // Creo lo Statement per l'esecuzione della query
         int rs = stmt.executeUpdate(sInsert);   // Ottengo il ResultSet dell'esecuzione della que
         stmt.close();   // Chiudo lo Statement
      } catch (Exception e) { 
          e.printStackTrace(); 
          errore = e.getMessage(); 
          System.err.println(sInsert+" non inserito!!!!!");
          insert = false;
      }

      return insert;
   }
    
    

   

   /**
    * Aggiorna un elemento del database.
    * Verrà prodotto il comando SQL: "UPDATE "+ nomeTabella+" SET "+campo+" = "+valore +" WHERE "+condizione;
    * @param nomeTabella nome della tabella
    * @param campo nome del campo che si vuole aggiornare
    * @param valore valore del campo che si vuole aggiornare
    * @param condizione condizione della query. Può essere null
    * @return
    * @throws SQLException 
    */
   public boolean update(String nomeTabella, String campo, String valore, String condizione) throws SQLException {
      int numero = 0;
      boolean risultato = false;
      String sModify;
      if(condizione==null) sModify = "UPDATE "+ nomeTabella+" SET "+campo+" = "+valore;
      else sModify = "UPDATE "+ nomeTabella+" SET "+campo+" = "+valore +" WHERE "+condizione;
      
      System.out.println(sModify);
      
      try {
         Statement stmt = connection.createStatement();
         numero = stmt.executeUpdate(sModify);
         risultato = true;
         stmt.close();
      } catch (Exception e) {
         e.printStackTrace();
         errore = e.getMessage();
         risultato = false;
      }
      return risultato;
   }

   /**
    * Elimina righe dal database.
    * produce il comando SQL: "DELETE FROM "+nomeTabella
    * @param nomeTabella
    * @return
    * @throws SQLException 
    */
   public boolean delete(String nomeTabella) throws SQLException{
    String sDelete = "DELETE FROM "+nomeTabella; 
    //System.out.println(sDelete);
      boolean risultato = false;
      try {
         Statement stmt = connection.createStatement();
         int numero = stmt.executeUpdate(sDelete);
         risultato = true;
         stmt.close();
      } catch (Exception e) {
         e.printStackTrace();
         errore = e.getMessage();
         risultato = false;
      }
      return risultato;
   }
   
   /**
    * Elimina righe dal database.
    * produce il comando SQL: "DELETE FROM "+nomeTabella+" WHERE "+campo+" = "+ valore
    * @param nomeTabella
    * @param campo
    * @param valore
    * @return
    * @throws SQLException 
    */
   public boolean delete(String nomeTabella, String campo, String valore) throws SQLException{
    String sDelete = "DELETE FROM "+nomeTabella+" WHERE "+campo+" = "+ valore; 
    //System.out.println(sDelete);
      boolean risultato = false;
      try {
         Statement stmt = connection.createStatement();
         int numero = stmt.executeUpdate(sDelete);
         risultato = true;
         stmt.close();
      } catch (Exception e) {
         e.printStackTrace();
         errore = e.getMessage();
         risultato = false;
      }
      return risultato;
   }
   
    /**
    * Elimina righe dal database.
    * Produce il comando SQL: "DELETE FROM "+nomeTabella+" WHERE "+condizione
    * @param nomeTabella
    * @param condizione
    * @return
    * @throws SQLException 
    */
    @Override
    public boolean delete(String nomeTabella, String condizione) throws SQLException{
    String sDelete = "DELETE FROM "+nomeTabella+" WHERE "+condizione; 
    System.out.println(sDelete);
    int numero = 0;
      boolean risultato = false;
      try {
         Statement stmt = connection.createStatement();
         numero = stmt.executeUpdate(sDelete);
         risultato = true;
         stmt.close();
      } catch (Exception e) {
         e.printStackTrace();
         errore = e.getMessage();
         risultato = false;
      }
      return risultato;
   }
     
   /**
     * Ritorna TRUE se la connessione con il Database è attiva
     * @return 
     */
   public boolean isConnected() { 
       return connesso; 
   }   
   
   /**
    * Ritorna il messaggio d'errore dell'ultima eccezione sollevata
    * @return 
    */
   public String getErrore() { 
       return errore; 
   }       
 
    /**
    * Ritorna il numero degli elementi di una tabella 
    * @param nomeTabella
    * @return 
    */
    @Override
    public int countElement(String nomeTabella) {
        String queryCount = "SELECT count(*) FROM "+nomeTabella;
        int count = -1;
        try {
         Statement stmt = connection.createStatement();     // Creo lo Statement per l'esecuzione della query
         ResultSet rs = stmt.executeQuery(queryCount);   // Ottengo il ResultSet dell'esecuzione della query
         rs.next();
         count = rs.getInt(1);
         rs.close();     // Chiudo il ResultSet
         stmt.close();   // Chiudo lo Statement
      } catch (Exception e) {
          e.printStackTrace();
          errore = e.getMessage(); 
      }

      return count;
    
    }
    
        /**
    * Ritorna il numero degli elementi di una tabella 
    * @param nomeTabella
    * @return 
    */
    @Override
    public int countElement(String nomeTabella, String condizione) {
        String queryCount = "SELECT count(*) FROM "+nomeTabella+ " where "+condizione;
        System.out.println(queryCount);
        int count = -1;
        try {
         Statement stmt = connection.createStatement();     // Creo lo Statement per l'esecuzione della query
         ResultSet rs = stmt.executeQuery(queryCount);   // Ottengo il ResultSet dell'esecuzione della query
         rs.next();
         count = rs.getInt(1);
         rs.close();     // Chiudo il ResultSet
         stmt.close();   // Chiudo lo Statement
      } catch (Exception e) {
          e.printStackTrace();
          errore = e.getMessage(); 
      }

      return count;
    
    }
    
    /**
     * Ritorna il massimo tra gli id del campo della tabella e 0. -1 in caso di errore.
     * @param campo colonna contente tipo integer
     * @param nomeTabella
     * @return 
     */
    @Override
    public int getMaxId( String nomeTabella, String campo){
         String queryCount = "SELECT max("+campo+") FROM "+nomeTabella;
         //System.out.println(queryCount);
         int count ;
         int countElement;
         countElement = countElement(nomeTabella);
         if(countElement==0) return 0;
         try {
         Statement stmt = connection.createStatement();     // Creo lo Statement per l'esecuzione della query
         ResultSet rs = stmt.executeQuery(queryCount);   // Ottengo il ResultSet dell'esecuzione della query
         rs.next();
         count = rs.getInt(1);
         rs.close();     // Chiudo il ResultSet
         stmt.close();   // Chiudo lo Statement
      } catch (Exception e) { 
          e.printStackTrace(); 
          errore = e.getMessage();
          count = -1; }
         
      return count;
    }

    /**
     * Ritorna true se l'elemento value esiste
     * @param nomeTabella
     * @param campo
     * @param value
     * @return 
     */
    @Override
     public boolean existElement (String nomeTabella, String campo, String value){
        System.out.println("exist "+nomeTabella+" "+campo+" "+value);
        ArrayList vec;
        try {
            vec = query(nomeTabella, "*" , campo+" = "+value );
        } catch (SQLException ex) {
            return false;
        }
         if(vec.size()>0) return true;
         else return false;         
     }
   
     /**
      * Ritorna true se la tabella ha almeno un elemento che rispetta la condizione.
      * @param nomeTabella
      * @param condition
      * @return 
      */
    @Override
      public boolean existElement (String nomeTabella, String condition){
         ArrayList vec;
        try {
            vec = query(nomeTabella, "*" ,condition);
        } catch (SQLException ex) {
            return false;
        }
         if(vec.size()>0) return true;
         else return false;         
     }

        // </editor-fold>

        // <editor-fold defaultstate="collapsed" desc="statistiche">

    
     /**
     * Ritorna il nome del componente su cui agisce un attacco.
     * (NB si suppone che l'attacco sfrutti le vulnerabilità di un componente solo)
     * @return 
     */
        public int getIdComponenteByAttacco(int idAttacco){
            String sQuery = "Select  componente.idComponente from componente left join vulnerabilita "
                    + "on vulnerabilita.idComponente = componente.idComponente left join vulnAttacco "
                    + "on vulnerabilita.idVulnerabilita = vulnAttacco.idVulnerabilita where idAttacco ="+idAttacco;    
            int idComponente;
        try {
            Statement stmt = connection.createStatement();     // Creo lo Statement per l'esecuzione della query
            ResultSet rs = stmt.executeQuery(sQuery);   // Ottengo il ResultSet dell'esecuzione della query
            rs.next();
            idComponente = rs.getInt(1);
            rs.close();     // Chiudo il ResultSet
            stmt.close();   //
         } catch (SQLException ex) {
            Logger.getLogger(DBConnector.class.getName()).log(Level.SEVERE, null, ex);
            return -1;
        }
            return idComponente;
        }
    
        
             /**
     * Ritorna il nome del componente su cui agisce un attacco.
     * (NB si suppone che l'attacco sfrutti le vulnerabilità di un componente solo)
     * @return 
     */
        public int getIdComponenteByVulnerabilità(int idVulnerabilità){
            String sQuery = "Select  componente.idComponente from componente left join vulnerabilita "
                    + "on vulnerabilita.idComponente = componente.idComponente where idVulnerabilita ="+idVulnerabilità;    
            int idComponente;
        try {
            Statement stmt = connection.createStatement();     // Creo lo Statement per l'esecuzione della query
            ResultSet rs = stmt.executeQuery(sQuery);   // Ottengo il ResultSet dell'esecuzione della query
            rs.next();
            idComponente = rs.getInt(1);
            rs.close();     // Chiudo il ResultSet
            stmt.close();   //
         } catch (SQLException ex) {
            Logger.getLogger(DBConnector.class.getName()).log(Level.SEVERE, null, ex);
            return -1;
        }
            return idComponente;
        }
        
        
        
        // </editor-fold>

     /**
    * Esegue un test per verificare la connessione
    */
   public void testConnetti()
   {
       if (connect()) System.out.println("Accesso al database eseguito con successo");
       else System.out.println("Accesso al database fallito");
   }
      
}
    

